#include "vtkActor.h"
#include "vtkAxisActor.h"
#include "vtkCamera.h"
#include "vtkCoordinate.h"
#include "vtkCubeAxesActor.h"
#include "vtkPlaneSource.h"
#include "vtkPolyDataMapper.h"
#include "vtkProperty.h"
#include "vtkProperty2D.h"
#include "vtkRegressionTestImage.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkSmartPointer.h"
#include "vtkStructuredGrid.h"
#include "vtkTextProperty.h"

#include "vtkCubeAxesActor.h"
#include "vtkOrientationMarkerWidget.h"
#include "vtkAxesActor.h"
#include "vtkCaptionActor2D.h"
#include <vtkCubeSource.h>
#include <vtkCubeAxesActor.h>

#include "vtkPolygon.h"
#include <array>

#include <vtkAnnotatedCubeActor.h>
#include <vtkAxesActor.h>
#include <vtkBandedPolyDataContourFilter.h>
#include <vtkCamera.h>
#include <vtkCaptionActor2D.h>
#include <vtkCellData.h>
#include <vtkColorSeries.h>
#include <vtkConeSource.h>
#include <vtkCubeSource.h>
#include <vtkElevationFilter.h>
#include <vtkLookupTable.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkOrientationMarkerWidget.h>
#include <vtkPolyDataMapper.h>
#include <vtkPropAssembly.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSmartPointer.h>
#include <vtkTextProperty.h>
#include <vtkTransform.h>
#include <vtkTransformPolyDataFilter.h>


int TestCubeAxes2DMode();
vtkSmartPointer<vtkActor> createRing();


int main(int, char*[])
{
    return TestCubeAxes2DMode();


    return EXIT_SUCCESS;
}


int TestCubeAxes2DMode()
{
    // Create plane source
    vtkSmartPointer<vtkPlaneSource> plane = vtkSmartPointer<vtkPlaneSource>::New();
    plane->SetXResolution(10);
    plane->SetYResolution(10);
    plane->SetCenter(0, 0, -1);
    plane->SetOrigin(-500, 500, -1);
    plane->SetPoint1(500, 500, -1);
    plane->SetPoint2(-500, -500, -1);

    // Create plane mapper
    vtkSmartPointer<vtkPolyDataMapper> planeMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    planeMapper->SetInputConnection(plane->GetOutputPort());
    vtkMapper::SetResolveCoincidentTopologyToPolygonOffset();

    // Create plane actor
    vtkSmartPointer<vtkActor> planeActor = vtkSmartPointer<vtkActor>::New();
    planeActor->SetMapper(planeMapper);
//    planeActor->GetProperty()->SetColor(.5, .5, .5);
    planeActor->GetProperty()->SetColor(0, 0, 0);
//    planeActor->GetProperty()->SetOpacity(false);



    // Create edge mapper and actor
    vtkSmartPointer<vtkPolyDataMapper> edgeMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    edgeMapper->SetInputConnection(plane->GetOutputPort());
    // move the lines behind the axes a tad
    edgeMapper->SetRelativeCoincidentTopologyLineOffsetParameters(0, 2);

    // Create edge actor
    vtkSmartPointer<vtkActor> edgeActor = vtkSmartPointer<vtkActor>::New();
    edgeActor->SetMapper(edgeMapper);
//    edgeActor->GetProperty()->SetColor(.0, .0, .0);
//    edgeActor->GetProperty()->SetColor(100, 100, 100);
    edgeActor->GetProperty()->SetColor(255, 0, 0);
    edgeActor->GetProperty()->SetRepresentationToWireframe();
    edgeActor->RotateX(180);

    // Create renderer
    vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
//    renderer->SetBackground(0., 0., 0.);
//    renderer->SetBackground(20, 20, 20);
//    renderer->GetActiveCamera()->SetFocalPoint(.0, .0, .0);
//    renderer->GetActiveCamera()->SetPosition(.0, .0, 2.5);

    // Create cube axes actor
    vtkSmartPointer<vtkCubeAxesActor> axes = vtkSmartPointer<vtkCubeAxesActor>::New();
    axes->SetCamera(renderer->GetActiveCamera());
//    axes->SetBounds(-.5, .5, -.5, .5, 0., 0.);
    axes->SetBounds(-500, 500, -500, 500, 0., 0.);
    axes->SetCornerOffset(.0);
    axes->SetXAxisVisibility(1);
    axes->SetYAxisVisibility(1);
    axes->SetZAxisVisibility(0);
    axes->SetUse2DMode(1);

    // Deactivate LOD for all axes
    axes->SetEnableDistanceLOD(0);
    axes->SetEnableViewAngleLOD(0);

    // Use red color for X axis
    axes->GetXAxesLinesProperty()->SetColor(1., 0., 0.);
    axes->GetTitleTextProperty(0)->SetColor(1., 0., 0.);
    axes->GetLabelTextProperty(0)->SetColor(1., 0., 0.);

    // Use green color for Y axis
    axes->GetYAxesLinesProperty()->SetColor(0., 1., 0.);
    axes->GetTitleTextProperty(1)->SetColor(0., 1., 0.);
    axes->GetLabelTextProperty(1)->SetColor(0., 1., 0.);

    axes->SetXAxisRange(0, 100.0);
    axes->SetYAxisRange(0, 50.0);


    // Add all actors to renderer
//    renderer->AddActor(planeActor);
    renderer->AddActor(edgeActor);
    renderer->AddActor(axes);

//    vtkSmartPointer<vtkActor> ringActor = createRing();
//    renderer->AddActor(ringActor);


    // Create render window and interactor
    vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
    renderWindow->AddRenderer(renderer);
    renderWindow->SetSize(800, 600);
    renderWindow->SetMultiSamples(0);
    vtkSmartPointer<vtkRenderWindowInteractor> interactor =
            vtkSmartPointer<vtkRenderWindowInteractor>::New();
    interactor->SetRenderWindow(renderWindow);


//    vtkSmartPointer<vtkCamera> camera = renderer->GetActiveCamera();
//    camera->SetPosition(0, 0, 1000);
//    camera->SetViewUp(0, 1, 0);
//    camera->SetParallelScale(500.0);
//    camera->ParallelProjectionOn();
//    renderer->ResetCameraClippingRange();

//    double allBounds[6];
//    renderer->ComputeVisiblePropBounds(allBounds);
//
//    std::cout << allBounds[0] << "-" << allBounds[1] << "-" << allBounds[2] << "-" << allBounds[3] << "-" << allBounds[4] << "-" << allBounds[5] << "-" << std::endl;
//
//    allBounds[0] -= 1000;
//    allBounds[1] += 1000;
//    allBounds[2] -= 1000;
//    allBounds[3] += 1000;
//    allBounds[4] -= 1000;
//    allBounds[5] += 1000;
//    renderer->ResetCameraClippingRange(allBounds);

//    std::cout << allBounds[0] << "-" << allBounds[1] << "-" << allBounds[2] << "-" << allBounds[3] << "-" << allBounds[4] << "-" << allBounds[5] << "-";






    renderWindow->Render();
    interactor->Start();

    return 0;
}


vtkSmartPointer<vtkActor> createRing() {

    const int RowCount = 36;
    const int ColCount = 40;
    const double RowDegree = vtkMath::Pi() * 2 / RowCount;
    const double Radius = 500;
    const int AreaAvgRadius = Radius / ColCount;
    const int ArcSegmentCount = 1;
    double ArcSegmentDegree = RowDegree / ArcSegmentCount;

    vtkNew<vtkCellArray> allPolygons;
    vtkNew<vtkPoints> allPoints;
    vtkNew<vtkPolyData> polygonPolyData;

    for (int i = 0; i < RowCount; ++i) {

        double degree = RowDegree * i;

        for (int j = 0; j < ColCount; ++j) {

            vtkNew<vtkPolygon> polygon;
            polygon->GetPointIds()->SetNumberOfIds((ArcSegmentCount + 1) * 2);
            vtkIdType numberOfPoints = allPoints->GetNumberOfPoints();

            double radius0 = j * AreaAvgRadius;
            double radius1 = (j + 1) * AreaAvgRadius;

            for (int k = 0; k < ArcSegmentCount + 1; ++k) {
                double d0 = degree + (ArcSegmentDegree) * k;
                double x0 = cos(d0) * radius0;
                double y0 = sin(d0) * radius0;
                allPoints->InsertNextPoint(x0, y0, 0.0);

                double d1 = degree + (ArcSegmentDegree) * k;
                double x1 = cos(d1) * radius1;
                double y1 = sin(d1) * radius1;
                allPoints->InsertNextPoint(x1, y1, 0.0);

                polygon->GetPointIds()->SetId(k, numberOfPoints + (ArcSegmentCount - k));
                polygon->GetPointIds()->SetId(k + ArcSegmentCount + 1, numberOfPoints + ArcSegmentCount + 1 + k);
            }

            allPolygons->InsertNextCell(polygon);
        }
    }

    polygonPolyData->SetPoints(allPoints);
    polygonPolyData->SetPolys(allPolygons);


//    vtkNew<vtkPolyDataMapper2D> mapper;
//    mapper->SetInputData(polygonPolyData);
//    vtkSmartPointer<vtkCoordinate> normCoords = vtkSmartPointer<vtkCoordinate>::New();
//    normCoords->SetCoordinateSystemToView();
//    mapper->SetTransformCoordinate( normCoords );

//    vtkNew<vtkActor2D> actor;
//    actor->SetMapper(mapper);
////    actor->GetProperty()->EdgeVisibilityOn();
//    actor->GetProperty();
//    renderer->AddActor2D(actor);

    vtkNew<vtkPolyDataMapper> mapper;
    mapper->SetInputData(polygonPolyData);

    vtkNew<vtkActor> actor;
    actor->SetMapper(mapper);
    actor->GetProperty()->EdgeVisibilityOn();
    actor->GetProperty();

    return actor;
}


